package org.metasketch.simulator.tools.channels;

import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;

import org.metasketch.demo.model.ActorRole;
import org.metasketch.demo.model.DEMOModel;
import org.metasketch.demo.model.TransactionKind;
import org.metasketch.simulator.petri.PetriNet;
import org.metasketch.simulator.petri.PetriNetSet;
import org.metasketch.simulator.petri.Transition;
import org.metasketch.simulator.resources.Resource;
import org.metasketch.simulator.resources.ResourceBank;
import org.metasketch.simulator.resources.ResourceBase;
import org.metasketch.simulator.resources.ResourceClass;
import org.metasketch.simulator.resources.ResourceRequirements;
import org.metasketch.simulator.tools.Registry;
import org.metasketch.simulator.tools.generic.Expression;
import org.metasketch.simulator.tools.generic.GenericInfo;
import org.metasketch.simulator.tools.generic.GenericInfoValidator;
import org.metasketch.simulator.tools.generic.ResourceProduction;
import org.metasketch.simulator.tools.generic.ResourceRequirement;
import org.metasketch.simulator.tools.generic.Variable;
import org.metasketch.simulator.tools.transactions.StepDefinition;
import org.metasketch.simulator.tools.transactions.StepDefinitionValidator;
import org.metasketch.simulator.tools.transactions.StepName;
import org.metasketch.simulator.transformation.PetriNetSimulationPackage;

import com.thoughtworks.xstream.XStream;

public class MainTransactionChannelLoader {

	protected static XStream getXStream() {
		XStream xstream = new XStream();
		xstream.autodetectAnnotations(true);

		xstream.processAnnotations(Expression.class);
		xstream.processAnnotations(Variable.class);
		xstream.processAnnotations(ResourceRequirement.class);
		xstream.processAnnotations(ResourceProduction.class);

		xstream.processAnnotations(GenericInfo.class);

		xstream.processAnnotations(StepDefinition.class);
		xstream.processAnnotations(Channel.class);
		xstream.processAnnotations(Transaction.class);

		xstream.processAnnotations(MainTransactionChannels.class);

		return xstream;
	}

	protected static MainTransactionChannels load(File file) throws Throwable {

		XStream xstream = getXStream();

		FileReader reader = new FileReader(file);
		MainTransactionChannels cfg = (MainTransactionChannels) xstream
				.fromXML(reader);
		reader.close();

		return cfg;

	}

	public static MainTransactionChannels getResources(DEMOModel model,
			PetriNetSimulationPackage simulationPackage, File file)
			throws Throwable {
		MainTransactionChannels cfg = load(file);

		ResourceBank bank = simulationPackage.getResources();
		Registry reg = simulationPackage.getRegistry();

		List<Transaction> transactions = cfg.getTransactions();

		for (Transaction transaction : transactions) {

			Object tran = reg.get(transaction.getAlias());
			if (tran == null
					|| !(tran instanceof org.metasketch.simulator.tools.transactions.Transaction))
				throw new Exception(
						"No transaction found or not the correct class for alias: "
								+ transaction.getAlias());

			List<Channel> channels = transaction.getChannels();
			for (Channel channel : channels) {

				channel.setChannelDefinitions(new ArrayList<ChannelDefinition>());

				// Verify channels aliases
				StringTokenizer st = new StringTokenizer(channel.getAliases());
				while (st.hasMoreTokens()) {
					String token = st.nextToken();
					ChannelDefinition channelDef = (ChannelDefinition) reg
							.get(token);
					if (channelDef == null)
						throw new Exception(
								"Can't find channel definition with alias: "
										+ token);
					channel.getChannelDefinitions().add(channelDef);

				}

				// verify steps
				List<StepDefinition> steps = channel.getSteps();
				for (StepDefinition step : steps) {
					StepDefinitionValidator.validate(step,
							transaction.getAlias(), model, simulationPackage);
				}
			}

		}

		return cfg;

	}

}
